/*
    This file is part of Posixcpp library.

    Posixcpp library is free software: you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Posixcpp library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU LesserGeneral Public
    License along with Posixcpp library. If not, see
    <http://www.gnu.org/licenses/>.
*/

/**
 * @file condition.hpp
 * @brief Condition variable class declaration
 */

#ifndef POSIX_THREADS_CONDITION_HPP_INCLUDED
#define POSIX_THREADS_CONDITION_HPP_INCLUDED

#include "posix_threads.hpp"
#include <ostream>

#include "posix_time_timespec.hpp"
#include "posix_threads_mutex.hpp"

namespace posix
{
namespace threads
{
/**
 * @class Condition
 * @brief Condition variable
 */
class Condition final
{
public:
    /**
	 * @class Attributes
	 * @brief Condition variable attribute
	 */
	class Attributes
	{
	public:
        /**
         * @property handle
         * @brief POSIX condition attribute C handle
         */

        /**
         * @brief handle property get
         */
		pthread_condattr_t & handle() { return m_handle; }
        /**
         * @brief handle property get overloaded const version
         */
		const pthread_condattr_t & handle() const { return m_handle; }
	private:
        /**
         * @brief handle
         */
        pthread_condattr_t m_handle;
    };
    
    Condition();
    /**
     * @brief Constructor
     *
     * @param mutexObj Default mutex object
     */
    Condition( Mutex & mutexObj );
    Condition( const Attributes & attrs );
    /**
	 * @brief Constructor with atributes
	 *
	 * @param attrs Attributes object to use
	 * @param mutexObj Default mutex object
	 */
	Condition( const Attributes & attrs, Mutex & mutexObj );
    /**
     * @brief destructor
     */
	~Condition();
	/**
	 * @brief Signal to all waiting threads
	 */
	void broadcast();
	/**
	 * @brief Signal to one of the waiting threads
	 */
	void signal();
	/**
	 * @brief Wait on condition
	 *
	 * @param mutexObj Mutex object to use, if NULL, default internal lock
	 *     will be used
	 */
	void wait( Mutex * mutexObj = NULL );
	/**
	 * @brief Timed wait on condition
	 *
	 * @param timeout Timeout for waiting
	 * @param mutexObj Mutex object to use, if NULL, default internal lock
	 *     will be used
	 */
	bool wait( time::Timespec timeout,  Mutex * mutexObj = NULL );

	const pthread_cond_t & handle() const { return m_handle; }
	pthread_cond_t & handle() { return m_handle; }

	/**
	 * @property mutex
	 * @brief Default mutex object
	 */

	 Mutex * mutex() { return m_lock; }
	 const Mutex * mutex() const { return m_lock; }
	 void setMutex( Mutex * mutex ) { m_lock = mutex; }

private:
    /**
     * @brief handle
     */
    pthread_cond_t m_handle;
    /**
     * @brief Default lock for CV
     */
	Mutex * m_lock;
};

}
}
#endif // POSIX_THREADS_CONDITION_HPP_INCLUDED
